/*
 * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package com.dona.imsidetector.socket;

import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

import com.dona.imsidetector.db.entity.Imsi;
import com.dona.imsidetector.fragment.DetectorFragment;
import com.dona.imsidetector.utils.DeviceUtil;
import com.dona.imsidetector.utils.IMSIUtil;
import com.xuexiang.xutil.common.StringUtils;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class UDPClient {

    private final int POOL_SIZE = 5;
    public  int CLIENT_PORT = 9001;

    private static final String TAG = "UDPClient";
    private static final long TIME_OUT = 2 * 1000;
    private static final long HEARTBEAT_MESSAGE_DURATION = 2 * 1000;
    private DatagramSocket client;
    private DatagramPacket receivePacket;
    private static final int BUFFER_LENGTH = 1024;
    private byte[] receiveByte = new byte[BUFFER_LENGTH];
    private String device;
    private int deviceId;
    private String server_ip;
    private String[] currFreq = new String[]{"0","0","0","0","0"};
    public static List<Imsi> imsilist;
    public static List<String> imsistrlist;
    private String scanText;
    private int imsi_status;
    private Message message;
    private Handler handler;
    private int deviceState;

    public UDPClient(String device, int deviceId, String server_ip, Handler handler ,int CLIENT_PORT){
        this.device = device;
        this.server_ip = server_ip;
        this.deviceId = deviceId;
        this.handler = handler;
        this.CLIENT_PORT = CLIENT_PORT;
        int cpuNumbers = Runtime.getRuntime().availableProcessors();
        mThreadPool = Executors.newFixedThreadPool(cpuNumbers * POOL_SIZE);
        Log.e(TAG, "UDPClient: " +device +"," +deviceId +"," +server_ip +","  );
    }


    public void startUdpConnect()  {
        try {
            if(client==null){
                client = new DatagramSocket(null);
                client.setReuseAddress(true);
                client.bind(new InetSocketAddress(CLIENT_PORT));
            }

            if (receivePacket == null) {
                // 创建接受数据的 packet
                receivePacket = new DatagramPacket(receiveByte, BUFFER_LENGTH);
            }

            if(imsilist==null)
                imsilist = new LinkedList();

            if(imsistrlist==null){
                imsistrlist = new LinkedList();
            }else{
                Log.e(TAG, "startUdpConnect: imsistrlist is not null" );
            }

            startUdpThread();
        } catch (SocketException e) {
            Log.e(TAG, "startUdpConnect: " + device+ e.getLocalizedMessage());
            e.printStackTrace();
        }

    }

    public List<Imsi> getImsilist(){
        return imsilist;
    }

    public List<String> getImsistrlist(){
        return imsistrlist;
    }

    public String getScanText(){
        return scanText;
    }
    public String getServer_ip(){
        return server_ip;
    }

    private boolean isThreadRunning = false;
    private long lastReceiveTime = 0;

    /**
     * 处理接受到的消息
     */
    private void receiveMessage() {
        while (isThreadRunning) {
            try {
                if (client != null) {
                    client.receive(receivePacket);
                }
                lastReceiveTime = System.currentTimeMillis();
                Log.d(TAG, "receive packet success...");
            } catch (Exception e) {
                Log.e(TAG, "UDP数据包接收失败！线程停止");
                stopUdpConnect();
                e.printStackTrace();
                return;
            }

            if (receivePacket == null || receivePacket.getLength() == 0) {
                Log.e(TAG, "无法接收UDP数据或者接收到的UDP数据为空");
                continue;
            }

            try {

                String strReceive = new String(receivePacket.getData(), 0, receivePacket.getLength());
                Log.e(TAG, strReceive + " from " + receivePacket.getAddress().getHostAddress() + ":" + receivePacket.getPort() );

                String addr = receivePacket.getAddress().getHostAddress();
                int addrLen = addr.length();
                Log.e(TAG, "receiveMessage: " + addr +"," + addrLen );
                int deviceIndex = Integer.valueOf(addr.substring(addrLen-1,addrLen));
                String deviceFact = "设备" + deviceIndex;
                if(strReceive.contains("STATE")){

                }
                if(strReceive.indexOf("103")==0){
                    String imsi_str = IMSIUtil.getData( strReceive,"imsi") ;
                    String time_str = IMSIUtil.getData( strReceive,"time") ;
                    String power_str = IMSIUtil.getData( strReceive,"ulSig") ;

                    Imsi imsi = new Imsi();
                    imsi.setImsi(imsi_str);
                    imsi.setLat(DetectorFragment.lat);
                    imsi.setLng(DetectorFragment.lng);
                    imsi.setTime(Long.valueOf(time_str));
                    imsi.setPower(Float.valueOf(power_str));




    //                    imsibd.put(imsi);
                        boolean fff = true;
                        for (int i = 0; i < imsilist.size(); i++) {
                            Imsi imsi1 = imsilist.get(i);
                            if (imsi1.getImsi().equals(imsi_str)) {
                                imsilist.remove(i);
                                imsistrlist.remove(i);
                                imsilist.add(0, imsi);

                                imsistrlist.add(0, imsi_str + "["+power_str+"][" + currFreq[deviceIndex] +"]  " + DeviceUtil.stampToDate(time_str));
                                fff = false;
                            }
                        }
                        if (fff) {
                            imsilist.add(imsi);
                            imsistrlist.add( imsi_str + "["+power_str+"][" + currFreq[deviceIndex] +"]  " + DeviceUtil.stampToDate(time_str));

                        }



    //                    XUtilsManager.getInstance().getDbManager().save(imsi);

    //                imsi_status = 1;
                    notice(DetectorFragment.RECEIVE_MSG_FLAG,scanText);
                }

                if(strReceive.indexOf("101") == 0){
                    currFreq[deviceIndex] = IMSIUtil.getData(strReceive,"FREQ");
                    String deviceStateStr = IMSIUtil.getData(strReceive,"STATE");
    //
    //                "CLOSED"， "STARTING"， "ACTIVED"，"STATE_CELL_RF_OPEN"
    //，"SYNC_FAIL"， "STOPPING" "PHY_CRASHED"
                    scanText = deviceFact  + "在线";
    //                Log.e(TAG, "receiveMessage: "+ DeviceState.CLOSED +", "+ DeviceState.CLOSED.getName() +", " +deviceStateStr );
                    if(!StringUtils.isEmpty(deviceStateStr)
                            && !deviceStateStr.contains(DeviceState.CLOSED)){

                        switch (deviceStateStr){
                            case "STARTING":
                                scanText = deviceFact  + DeviceState.STARTING.getName();
                                break;
                            case "ACTIVED":
                                scanText = deviceFact  + DeviceState.ACTIVED.getName();
                                break;
                            case "STATE_CELL_RF_OPEN":
                                scanText = deviceFact  + DeviceState.STATE_CELL_RF_OPEN.getName();
                                break;
                            case "SYNC_FAIL":
                                scanText = deviceFact  + DeviceState.SYNC_FAIL.getName();
                                break;
                            case "STOPPING":
                                scanText = deviceFact  + DeviceState.STOPPING.getName();
                                break;
                            case "PHY_CRASHED":
                                scanText = deviceFact  + DeviceState.PHY_CRASHED.getName();
                                break;
                            default:
                                break;
                        }
                    }

                    notice(DetectorFragment.SERVER_STATUS_CHANGE,scanText);
                }else if(strReceive.indexOf("116") == 0){
    //                isOnScaning = true;
                    scanText = deviceFact  + "扫描中";
                    notice(DetectorFragment.SERVER_STATUS_CHANGE,scanText);
                }

            } catch (Exception e) {
                e.printStackTrace();
            }


            //解析接收到的 json 信息
//            103 OneUeInfoIndi PS_WL S2A4A2109059 time[4562] taType[TA_REQ] imsi[460023148087839] imei[000000000000000] ulSig[93] ulTa[14] bl_indi[0]  from 192.168.1.90:9001
            // 每次接收完UDP数据后，重置长度。否则可能会导致下次收到数据包被截断。
            if (receivePacket != null) {
                receivePacket.setLength(BUFFER_LENGTH);
            }
            try {
                clientThread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


    private void notice(int what,String arg1){
        message = new Message();
        message.what = what;
        message.obj = arg1;
        Log.e(TAG, "notice: " + arg1 );
        this.handler.sendMessage(message);
    }

    /**
     * 开启发送数据的线程
     */
    private void startUdpThread() {
        clientThread = new Thread(new Runnable() {
            @Override
            public void run() {
                Log.d(TAG, "clientThread is running...");
                receiveMessage();
            }
        });
        isThreadRunning = true;
        clientThread.start();

        startHeartbeatTimer();
    }


    private Thread clientThread;
    private HeartbeatTimer timer;

    /**
     * 启动心跳，timer 间隔十秒
     */
    private void startHeartbeatTimer() {
        timer = new HeartbeatTimer();
        timer.setOnScheduleListener(new HeartbeatTimer.OnScheduleListener() {
            @Override
            public void onSchedule() {
                Log.d(TAG, server_ip + "timer is onSchedule..." );
                String string = "HeatBeat";
                sendMessage(string);


                long duration = System.currentTimeMillis() - lastReceiveTime;
                Log.d(TAG, server_ip +"duration:" + duration);
                if (duration > TIME_OUT) {//若超过两分钟都没收到我的心跳包，则认为对方不在线。
                    Log.d(TAG, server_ip + "超时，对方已经下线");
                    scanText = device + "离线，等待设备上线";
                    // 刷新时间，重新进入下一个心跳周期
                    lastReceiveTime = System.currentTimeMillis();
                } else if (duration > HEARTBEAT_MESSAGE_DURATION) {//若超过十秒他没收到我的心跳包，则重新发一个。
//                    String timeMillis = String.valueOf(System.currentTimeMillis());
//                    Log.e(TAG, "onSchedule: " + timeMillis );

                }
            }

        });
        timer.startTimer(0, 1000 * 2);
    }

    public void stopUdpConnect() {
        isThreadRunning = false;
        receivePacket = null;
        if (clientThread != null) {
            clientThread.interrupt();
        }
        if (client != null) {
            client.close();
            client = null;
        }
        if (timer != null) {
            timer.exit();
        }
    }

    private ExecutorService mThreadPool;
    /**
     * 发送心跳包
     *
     * @param message
     */
    public void sendMessage(String message) {

        mThreadPool.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    InetAddress targetAddress = InetAddress.getByName(server_ip);
                    DatagramPacket packet = new DatagramPacket(message.getBytes(), message.length(), targetAddress, CLIENT_PORT);

                    if(client == null){
//                        startUdpConnect();
                        startUdpConnect();
                    }
                    client.send(packet);

                    // 数据发送事件
                    Log.d(TAG, server_ip + "数据发送成功:" + message);

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });



    }



}

enum DeviceState implements CharSequence {

    CLOSED("关闭",1),
    STARTING("启动中",2),
    ACTIVED("运行中",3),
    STATE_CELL_RF_OPEN("扫描中",4),
    SYNC_FAIL("同步失败",5),
    STOPPING("关闭中",6),
    PHY_CRASHED("异常",7);

    private String name;
    private int index;

    DeviceState(String name, int index) {
        this.name = name;
        this.index = index;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getIndex() {
        return index;
    }
    public void setIndex(int index) {
        this.index = index;
    }

    @Override
    public int length() {
        return 0;
    }

    @Override
    public char charAt(int index) {
        return 0;
    }

    @Override
    public CharSequence subSequence(int start, int end) {
        return null;
    }
}